#include<iostream>
#include<cstdio>
#include<string>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#include<cstdlib>
#include"comm.hpp"

const int gdefaultid = -1;
const int gsize = 4096;
const std::string pathname = ".";
const int projid = 0x66;
const int gmode = 0666;

#define CREATER "creater"
#define USER "user"

class Shm
{
private:
    void CreateHelper(int flg)
    {
        printf("key: 0x%x", _key);
                        //键值 大小   权限 
        _shmid = shmget(_key, _size, flg);
        if(_shmid < 0)
            ERR_EXIT("shmget");
        printf("shmid: %d", _shmid);
    }
    //创建共享内存
// 1. 核心参数
// pathname：需是系统中存在的文件 / 目录路径（如 ./、/tmp），作为生成键值的基准，确保多进程用相同路径时键值基础一致；路径无效则返回 -1。
// proj_id：8 位非零整数（如 0x66、123），用于区分同一路径下的不同 IPC 资源；仅低 8 位有效（0~255），超出部分被忽略。
// 2. 返回值
// 成功：返回非负 key_t 类型键值（IPC 资源唯一标识）。
// 失败：返回 -1，通过 errno 提示错误（如路径不存在、权限不足）。
    void Create()
    {
        CreateHelper(IPC_CREAT | IPC_EXCL | gmode);
    }
    void Get()
    {
        CreateHelper(IPC_CREAT);
    }
    void Attach()//将申请的共享内存与当前进程相连接
    {
        _start_mem = shmat(_shmid, nullptr, 0);
        if((long long)_start_mem < 0)
            ERR_EXIT("shmat");
        printf("attach success\n");
    }
    void Detach()//将申请的共享内存与当前进程相脱离
    {
        int n = shmdt(_start_mem);
        if(n == 0)
            printf("detach success\n");
    }
    void Destroy()
    {
        Detach();
        if(_usertype == CREATER)
        {
            int n = shmctl(_shmid, IPC_RMID, nullptr);
            if(n == 0)
                printf("shmctl delete shm: %d success!\n", _shmid);
            else
            {
                ERR_EXIT("shmctl");
            }
        }
    }

public:
    Shm(const std::string &pathname, int projid, const std::string &usertype)
    :_shmid(gdefaultid),
    _size(gsize),
    _start_mem(nullptr),
    _usertype(usertype) 
    {
        //只要 pathname 存在且 projid 相同，ftok 就会生成 同一个 key 值
        _key = ftok(pathname.c_str(), projid);
        if(_key < 0)
            ERR_EXIT("ftok");
        if(_usertype == CREATER)
            Create();
        else if(_usertype == USER)
            Get();
        else
        {}
        Attach();
    }
    void *VirtualAddr()
    {
        printf("VirtualAddr: %p\n", _start_mem);
        return _start_mem;
    }
    int Size()
    {
        return _size;
    }
    void Attr()
    {
        struct shmid_ds ds;
        int n = shmctl(_shmid, IPC_STAT, &ds);
        if(n < 0)  // 补充错误判断
            ERR_EXIT("shmctl");
        printf("shm_segsz:%ld\n", ds.shm_segsz);
        printf("key: 0x%x\n", ds.shm_perm.__key);
    }
    ~Shm()
    {
        std::cout << _usertype << std::endl;
        if(_usertype == CREATER)
            Destroy(); 
    }

private:
    int _shmid;
    key_t _key;
    int _size;
    void *_start_mem;
    std::string _usertype;
};















